
function load_player()

	player = {

		name = "",
		range_x = range_x,
		range_y = range_y,
		health = 100,
		max_health = 100,
		alive = true,
		gender = "",
		speed = 100,
		fire_rate = 0.5,
		scourge_res  = 0,
		res_lev = 1,
		quota = 100,
		resist = 1,
		light = false,
		battery = 1000,--0,
		max_bat = 1000,
		light_cost = 5,
		lock_control = false,
		inventory = {},
		conditions = {},
		splatters_cleaned = 0,
		noclip = true,
		--mouse_mode = "basic",
		log = {
			record = {},
			w = function( log ) 

					player.log.record[#player.log.record+1] = "[ " .. os.date() .. " ]" .. 
						": " .. log 
				end,
			r = function() 
					local s = ""
					for i in #player.log.record do 
						s = s .. player.log.record[i] .. "\n"
					end
					return s
				end,

		},


	}


	-- commands to control the player
	player.controls = {
		["up"] = function (lm)
				if p_collision(lm.layout, "up") then
					map_y = map_y - 1
				end
				draw_map(lm.layout)
				--print("mapx : ", map_x, "mapy : ", map_y)
			end,
		["down"] = function (lm)
				if p_collision(lm.layout, "down") then
					map_y = map_y + 1
				end
				draw_map(lm.layout)
				--print("mapx : ", map_x, "mapy : ", map_y)
			end,

		["right"] = function (lm)
				if p_collision(lm.layout, "right") then
					map_x = map_x + 1
				end
				draw_map(lm.layout)
				--print("mapx : ", map_x, "mapy : ", map_y)
			end,
		["left"] = function (lm)
				if p_collision(lm.layout, "left") then
					map_x = map_x - 1
				end
				draw_map(lm.layout)

				--print("mapx : ", map_x, "mapy : ", map_y)
			end,
		["light_toggle"] = function (x)

				if player.light then
					player.light = false
					Feature:set_lit_all (false)
					Item:set_lit_all (false)
					Enemy:set_lit_all (false)
				elseif player.battery > 0 then
					player.light = true
				else
					draw_text("Not enough energy.")
				end

			end,
		["unlock_player"] = function (x)

				if player.lock_control == true then player.lock_control = false end


			end,

		["debug"] = function (x)

				debug.debug()

			end,

		["pickup"] = function(x)

				local items = Item:player_collision()

				if items then

					items[1]:pickup()

				end

			end,

		["view_inventory"] = function(x)
				print('viewing inventory')

				local inv = player.inventory
				local msg_opt = {}

				msg_opt.name = "Inventory"

				if #inv > 0 then
					
					msg_opt.choices = {}

					for i = 1, #inv do
						if inv[i] then
							local s = inv[i].name
							msg_opt.choices[#msg_opt.choices+1] = s
						end

					end

					player.cancel_choice_id = #msg_opt.choices+1

					msg_opt.choices[player.cancel_choice_id] = 'Cancel'

					
					msg_opt.x = center_x
					msg_opt.y = center_y

					msgs[#msgs+1] = _navi:new('', msg_opt)

					player.picking_inv = true

				else

					msg_opt.y = center_y
					msg_opt.x = center_x

					msgs[#msgs+1] = _navi:new('No inventory items', msg_opt)

				end


			end,
		["goto_menu"] = function(x)
				gs:gotoState('Menu')
			end,



	}

	-- keys which tie to commands to control the player
	player.binds = {
		["up"] = function(x) player.controls["up"](x) end,
		["down"] = function(x) player.controls["down"](x) end,
		["right"] = function(x) player.controls["right"](x) end,
		["left"] = function(x) player.controls["left"](x) end,
		["w"] = function(x) player.controls["up"](x) end,
		["s"] = function(x) player.controls["down"](x) end,
		["d"] = function(x) player.controls["right"](x) end,
		["a"] = function(x) player.controls["left"](x) end,
		["r"] = function(x) player.controls["light_toggle"](x) end,
		["`"] = function(x) player.controls["debug"](x) end,
		["\\"] = function(x) player.controls["pickup"](x) end,
		["e"] = function(x) player.controls["pickup"](x) end,
		["i"] = function(x) player.controls["view_inventory"](x) end,
		["escape"] = function(x) player.controls["goto_menu"](x) end,




	}

	-- research 'level' system
	research_quotas = {
		[1] = function (x) player.quota = 100; player.resist = 0.9 end,
		[2] = function (x) player.quota = 500; player.resist = 0.8 end,
		[3] = function (x) player.quota = 1500; player.resist = 0.7 end,
		[4] = function (x) player.quota = 3000; player.resist = 0.6 end,
		[5] = function (x) player.quota = 5000; player.resist = 0.5 end,

	}



	player_x = dOX+((player.range_x)*(tile_size*scale))/2+(tile_size/2)*scale
	player_y = dOY+((player.range_y)*(tile_size*scale))/2+(tile_size/2)*scale
	player_x = player_x+((tile_size*scale)/2)
	player_y = player_y+((tile_size*scale)/2)

	player.body = love.physics.newBody(world, player_x, player_y, "dynamic")
	player.light_body = love.physics.newBody(world, player_x, player_y, "dynamic")



end

function p_heal(amount)

	print(" attempting to heal player for " .. amount)

	if player.health < player.max_health then
		--print("player not at max health")
		local th = player.health + amount
		if th > player.max_health then
			player.health = player.max_health
			
		else
			player.health = th

		end

		return true

	end

	return false

end

function p_pick_callback(pick, msg)

	if pick == player.cancel_choice_id then
		return
	end

	if player.picking_inv then
		print("player picked inv item" .. pick)
		player.picking_inv = nil

		local msg_opt = {}
		msg_opt.x = center_x
		msg_opt.y = center_y
		msg_opt.choices = {
			'Use',
			'Examine',
			'Drop',
			'Cancel'
		}
		
		player.cancel_choice_id = 4

		msgs[#msgs+1] = _navi:new('', msg_opt)

		player.picking_item_opts = true
		player.picked_item = pick

		return

	end

	if player.picking_item_opts then
		print("picked item opt " .. pick)
		player.picking_item_opts = nil
		local inv = player.inventory
		local p = player.picked_item

		if pick == 1 then
			inv[p]:use()
		elseif pick == 2 then
			inv[p]:examine()
		elseif pick == 3 then
			inv[p]:drop()
		end


		player.picked_item = nil
		--clean_msg()

		return
	end

end

function p_add_inventory (item)

	if item then

		local inv_count = #player.inventory+1

		item.id = inv_count
		item.in_inv = true

		player.inventory[inv_count] = item


	end

end
--!
function p_rem_inventory (itemid)

	if itemid ~= nil then
		
		table.remove(player.inventory, itemid)

		-- reassign element id's in case table.remove
		-- leaves a gap
		if itemid ~= #player.inventory+1 then
			for i = itemid, #player.inventory+1 do
				if player.inventory[i] and i > 0 then
					player.inventory[i].id = i
				end
			end
		end
	end

end


function p_damage(damage, resist)

	if resist then
		damage = damage*resist
	end

	player.health = player.health - damage

	if player.health < 0 then
		print("you died")
		player.alive = false
	end


end

function p_light_energy(light_count)

	local chg_speed = 0.5

	if player.light then
		--print("light on")
		--print(light_count)
		light_count = light_count+1

		if light_count >= love.timer.getFPS()*chg_speed then
			-- drain juice every chg_speed
			light_count = 0
			player.battery = player.battery - player.light_cost
		end

		if player.battery < player.light_cost then
			-- turn off the light if we're outta juice

			player.controls["light_toggle"]()

		end

		return light_count

	end

	return light_count

end

function p_light_beam_collide(entX, entY)



	local sX, sY = p_tur_ninety()
	local bX, bY = player.body:getWorldCenter()
	local mX, mY = love.mouse.getPosition()

	sX = sX + bX
	sY = sY + bY

	local angle = findRotation(sX, sY, mX, mY)
	local eX, eY = turret(3*(tile_size*scale), player.body:getAngle()-deg_15_rad)
	local fX, fY = turret(3*(tile_size*scale), player.body:getAngle()+deg_30_rad)
	--love.graphics.line(sX, sY, player_x+eX, player_y+eY)
	--love.graphics.line(sX, sY, player_x+fX, player_y+fY)

	local dx1, dy1 = sX-(player_x+eX), sY-(player_y+eY)
	local dx2, dy2 = sX-(player_x+fX), sY-(player_y+fY)
	local dxm1, dym1 = gOrL(sX, player_x+eX), gOrL(sY, player_y+eY)
	local dxm2, dym2 = gOrL(sX, player_x+fX), gOrL(sY, player_y+fY)

	local p1 = { x = sX, y = sY }
	local p2 = { x = player_x+eX, y = player_y+eY }
	local p3 = { x = player_x+fX, y = player_y+fY }
	local p = { x = entX, y = entY }

	local alpha = ((p2.y - p3.y)*(p.x - p3.x) + (p3.x - p2.x)*(p.y - p3.y)) /
        ((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y))

	local beta = ((p3.y - p1.y)*(p.x - p3.x) + (p1.x - p3.x)*(p.y - p3.y)) /
       ((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y))

	local gamma = 1.0 - alpha - beta

	-- triangulates that shit

	if alpha > 0 and beta > 0 and gamma > 0 then
		--print("light true")
		return true
	else
		--print("light false")
		return false

	end

	--love.graphics.polygon('fill', sX, sY,
	--	player_x+eX, player_y+eY, player_x+fX, player_y+fY)

end

function p_research()


	local res = player.scourge_res
	local rl = player.res_lev

	--print(table.tostring(research_quotas))

	if research_quotas[rl] then
		--print("quota found : ", player.quota)
		research_quotas[rl]()

	else
		player.quota = res^rl

	end


	if res >= player.quota then

		player.res_lev = player.res_lev+1
	end

end

function p_update(dt)

	local mX, mY = love.mouse.getPosition()
	local aS = (3*math.pi)/2
	local aF = math.pi/2
	distance_x = (mX-player_x)
	distance_y = (mY-player_y)
	local dX = (mX-player_x)
	local dY = (mY-player_y)
	local mR = math.atan2(mY-player_y, mX-player_x)
	local hyp = math.sqrt((dX*dX)+(dY*dY))

	player.body:setPosition(player_x, player_y)
	player.body:setAngle( mR )
	p_research()


end

function p_turret(delta)

	local Point = { origin_x = player.body:getX(), origin_y = player.body:getY(),
		angle = player.body:getAngle() }

	Point.angle = Point.angle+delta

	local offX = p_turret_rad*math.cos(Point.angle)
	local offY = p_turret_rad*math.sin(Point.angle)

	Point = nil

	return offX, offY


end

function turret(radius, angle)

	local offX = radius*math.cos(angle)
	local offY = radius*math.sin(angle)

	return offX, offY


end

function turret2(x, y, radius, angle)

	local offX = radius*math.cos(angle)
	local offY = radius*math.sin(angle)

	offX = offX+x
	offY = offY+y

	return offX, offY


end

function p_tur_ninety()

	local x, y = p_turret(ninety_deg_rad)

	--print("turned x : ", x, "turned y :", y)

	return x, y

end

function p_fire_proj(proj_type, x, y)

	local pX = dOX+((player.range_x)*(tile_size*scale))/2+(tile_size/2)*scale
	local pY = dOY+((player.range_y)*(tile_size*scale))/2+(tile_size/2)*scale


	pX = pX+(tile_size*scale)/2
	pY = pY+(tile_size*scale)/2

	local angle = math.atan2((y - pY), (x-pX))



	--print("angle : ", angle)

	angle = math.rad(angle)

	if proj_type == "basic" then
		local sX, sY = p_tur_ninety()
		local bX, bY = player.body:getWorldCenter()

		sX = sX + bX
		sY = sY + bY
		--print("v.x : ", v.x, "v.y : ", v.y)
		spawn_proj(projectiles, sX, sY, x, y, bullet_img, bb_anim:clone())

	end


end

function p_control(key, unicode, lm)

	if gs:isInState("NewGame") then		
		if key == 'escape' then
			player.binds[key](lm)
		end
	end


	if not player.lock_control then

		if player.binds[key] then

			player.binds[key](lm)
		else
			print(key.." not bound")

		end



		local feat = feature_collider()

		if feat then

			local pX = map_x+view_center_x
			local pY = map_y+view_center_y

			features[pY][pX]:use()

		end

		

		if key == 'return' then



		end


		--[[

		local items = Item:player_collision()

		if items then

			for i = 1, #items do

				print("walked over " .. items[i].name)
				items[i]:pickup()

			end

		end

		]]

		pX = map_x+view_center_x
		pY = map_y+view_center_y
		--print("pX : ", pX, "pY : ", pY)

	elseif key == arc.btn.ent then

		player.lock_control = false

	end

end

function p_collision(grid, dir)

	--local pX = dOX+((player.range_x)*(tile_size*scale))/2+(tile_size/2)*scale
	--local pY = dOY+((player.range_y)*(tile_size*scale))/2+(tile_size/2)*scale








	if not player.noclip then
		if dir == "right" then
			if p_can_collide(grid[pY][pX+1]) then
				return true
			else
				return false
			end
		elseif dir == "left" then
			if p_can_collide(grid[pY][pX-1]) then
				return true
			else
				return false
			end
		elseif dir == "up" then
			if p_can_collide(grid[pY-1][pX]) then
				return true
			else
				return false
			end
		elseif dir == "down" then
			if p_can_collide(grid[pY+1][pX]) then
				return true
			else
				return false
			end
		end
	else
		return true
	end



end

function p_can_collide(tile_type)

	-- false = tiles which the player cannot pass through

	if type(tile_type) == "number" then

		if tile_type == wall_tile then
			return false
		elseif tile_type == wall_damaged_tile then
			return false
		elseif tile_type == floor_tile then
			return true
		elseif tile_type == space_tile then
			return true
		elseif tile_type == med_floor then
			return true
		elseif tile_type == med_wall then
			return false
		end

	else

		print("tile type not a number")
	end

end

--[[
function p_controls(dt)

	if love.keyboard.isDown("right") then
		player.x = player.x + (player.speed * dt)
	elseif love.keyboard.isDown("left") then
		player.x = player.x - (player.speed * dt)
	end

	if love.keyboard.isDown("up") then
		player.y = player.y - (player.speed * dt)
	elseif love.keyboard.isDown("down") then
		player.y = player.y + (player.speed * dt)
	end

end
]]

function p_range (x, y)
	local distX = data.player.x - x
	local distY = data.player.y - y
	local absDistX = math.abs(distX)
	local absDistY = math.abs(distY)
	return absDistX, absDistY
end

function p_range_t(x,y)
	local distX = data.player.x - x
	local distY = data.player.y - y
	return distX, distY
end

function p_finished_turn()


end

function p_loc(x,y)
	if data.player.x == x and data.player.y == y then
		return true
	else
		return false
	end
end

function p_death()

end


function p_fov(x, y)

	distX, distY = p_range(x,y)

	if distX == player_fov*tile_size
		and distY == player_fov*tile_size then
		return false
	elseif distX <= player_fov*tile_size
		and distY <= player_fov*tile_size then
		return true
	else
		return false
	end


end

function p_input_text(key, unicode)

	if key == 'backspace' then
		data.player.con_text = string.sub(data.player.con_text,1,-2)
	elseif unicode > 31 and unicode < 127 then

		data.player.con_text = data.player.con_text .. string.char(unicode)
	elseif key == 'escape' or key == '`' then
		data.player.text_input = false
	elseif key == 'return' then
		parse_con(data.player.con_text)
		data.player.text_input = false
	end

end

function p_save(player)

	love.filesystem.write("player.gv", table.show(player, "loaded_player"))

end

function p_random_spawn(player, grid)

	local placed = false
	local potentialX = 0
	local potentialY = 0

	while placed == false do
		potentialX = RNG:random(grid_size)
		potentialY = RNG:random(grid_size)
		if grid[potentialY][potentialX].type == "floor" then
			player.x = potentialX*tile_size
			player.y = potentialY*tile_size
			placed = true
		end
	end

end
